package solver.moves;

import java.util.Collections;
import java.util.Iterator;
import java.util.List;

import model.BalanceObjective;
import model.MachineSelector;
import model.Solution;
import model.SolverEnvironment;

public class BalanceCostEliminator extends AbstractComplexMove{
	
	MachineSelector ms;
	
	public BalanceCostEliminator(SolverEnvironment env, MachineSelector ms) {
		super(env);
		this.ms = ms;
	}
	
	@Override
	public boolean performMove() {
		boolean success = false;
		long init_cost=getCc().getNewSolutionCost();
		long local_cost = init_cost;
		Solution pot_sol = env.getPotentialSolution();

		//		boolean useLocal = random.nextBoolean();

		//TODO: Sort by balance cost???
		
//		int start = getRandom().nextInt(getProblem().M);
		int end = Math.min(10+getRandom().nextInt(20), getProblem().M);
		ms.updateStructureWithBalance();
		List<Integer> ml = ms.getMachineIds();
outer:		for (int i = 0; i<end;i++) {
			int curr_m1_index = ml.get(i);
			local_cost=getCc().getNewSolutionCost();
			long bc = pot_sol.balance_cost_contribution_zipped[curr_m1_index];
//			long lc = cc.getLoadCost(current_solution, curr_m1_index);

			if(bc<=0) continue;
//			if(bc<=lc) continue;

		int jend = Math.min(i+end, getProblem().M);	
otherM:	for(int j=i+1; j<jend;j++){
//			for(int j=ml.size()-1; j>i;j--){
				int m2 =  ml.get(j);
				//TODO: Use structure in order to not recalclulate it 
				if(pot_sol.balance_cost_contribution_zipped[m2]>bc)
					continue;

				List<Integer> m2pl = pot_sol.getProcessesForMachine(m2);
				Collections.shuffle(m2pl,getRandom());

				for(int k=0; k<m2pl.size();k++){
					int p2 = m2pl.get(k);
					if (testWithoutMove(p2, m2, curr_m1_index)){
						long delta=getCc().getProcessMoveToMachineCost(pot_sol, p2, m2, curr_m1_index);		
						//					if((useLocal && new_cost>local_cost) || new_cost>init_cost){
						if(delta<=0){
							makeMove(p2, m2, curr_m1_index);
							getCc().updateNewSolutionCost();
							success=true;
							bc = getCc().getBalanceCost(pot_sol, curr_m1_index);
//							if(bc<=0)
//								break outer;
						}
					}
				}
			}
//			if(success)
//				break;
		}
		
		getCc().clearDelta();

		return success;
	}
}
